<#assign beanName = table.pojoName/>
<#assign properties = table.properties/>
<#assign properties2 = table.properties2/>
<#assign propertiesAnColumns = table.propertiesAnColumns/>
<#assign ids = table.primaryKey/>
<#assign keys = properties?keys/>
package ${table.pojoMapperPackPath};

import com.fast.orm.data.*;
import com.fast.orm.exec.DeleteExecution;
import com.fast.orm.exec.InsertExecution;
import com.fast.orm.exec.SelectExecution;
import com.fast.orm.exec.UpdateExecution;
import com.fast.orm.many.JoinDirection;
import com.fast.orm.utils.FastValueUtil;
<#if !conf.exInlinePojo>
import ${table.pojoClassPackPath};
</#if>
<#if conf.exInlinePojo>
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.Column;
import java.io.Serializable;
import com.fast.orm.mapper.FastBean;
<#list table.packages as package>
${package}
</#list>
<#if conf.useLombok>
import lombok.Data;
</#if>
<#if conf.usePOJOSwagger2>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
</#if>
/**
* ${table.tableDesc}
*/
public class ${beanName}Ex {
    public static ${beanName}Insert INSERT() {
        return new ${beanName}Insert();
    }
    public static ${beanName}Delete DELETE() {
        return new ${beanName}Delete();
    }
    public static ${beanName}Update UPDATE() {
        return new ${beanName}Update();
    }
    public static ${beanName}Select<${beanName}> SELECT() {
        return new ${beanName}Select<>();
    }
    public static <R>${beanName}Select<R> SELECT(Class<R> returnClass) {
        return new ${beanName}Select<>(returnClass);
    }
    public static class ${beanName}Insert{
        private final DataPackage dataPackage;
        public ${beanName}Insert() {
            this.dataPackage = new DataPackage(${beanName}.class);
        }
        public InsertExecution<${beanName}> EXEC() {
            return new InsertExecution<>(dataPackage);
        }
    }
    public static class ${beanName}Delete {
        private final DataPackage dataPackage;
        private ${beanName}Delete() {
            this.dataPackage = new DataPackage(${beanName}.class);
        }
        public DeleteExecution EXEC() {
            return new DeleteExecution(dataPackage);
        }
        public ${beanName}Where<DeleteExecution> WHERE() {
            return new ${beanName}Where<>(dataPackage, new DeleteExecution(dataPackage));
        }
    }
    public static class ${beanName}Update extends ${beanName}Fields<Update<${beanName}Update>> {
        private ${beanName}Update() {
            this.dataPackage = new DataPackage(${beanName}.class);
            this.t = new Update<>(dataPackage, this);
        }
        public ${beanName}Update set(${beanName} pojo){
            FastValueUtil.setUpdateBeanValue(dataPackage, pojo);
            return this;
        }
        public UpdateExecution<${beanName}> EXEC() {
            return new UpdateExecution<>(dataPackage);
        }
        public ${beanName}Where<UpdateExecution<${beanName}>> WHERE() {
            return new ${beanName}Where<>(dataPackage, new UpdateExecution<>(dataPackage));
        }
    }
    public static class ${beanName}Select<R> extends ${beanName}Fields<Select<${beanName}Select<R>>> {
        private ${beanName}Select() {
            this.dataPackage = new DataPackage(${beanName}.class);
            this.t = new Select<>(dataPackage, this);
        }
        private ${beanName}Select(Class<R> returnClass) {
            this.dataPackage = new DataPackage(${beanName}.class,returnClass);
            this.t = new Select<>(dataPackage, this);
        }
        public <T>${beanName}Join<T,R> LEFT_JOIN(BaseMapper<T> baseMapper, String... tableAlias) {
            return new ${beanName}Join<>(dataPackage,ConditionSetting.joinInfo(dataPackage, JoinDirection.LEFT_JOIN,baseMapper, tableAlias));
        }
        public <T>${beanName}Join<T,R> RIGHT_JOIN(BaseMapper<T> baseMapper, String... tableAlias) {
            return new ${beanName}Join<>(dataPackage,ConditionSetting.joinInfo(dataPackage, JoinDirection.RIGHT_JOIN,baseMapper, tableAlias));
        }
        public <T>${beanName}Join<T,R> INNER_JOIN(BaseMapper<T> baseMapper, String... tableAlias) {
            return new ${beanName}Join<>(dataPackage,ConditionSetting.joinInfo(dataPackage, JoinDirection.INNER_JOIN,baseMapper, tableAlias));
        }
        public ${beanName}OrderBy<R> ORDER_BY() {
            return new ${beanName}OrderBy<>(dataPackage);
        }
        public SelectExecution<R> EXEC() {
            return new SelectExecution<>(dataPackage);
        }
        public ${beanName}Where<SelectExecution<R>> WHERE() {
            return new ${beanName}Where<>(dataPackage, new SelectExecution<>(dataPackage));
        }
    }

    public static class ${beanName}Join<P,R> extends ${beanName}Select<R>{
        private final DataPackage.JoinInfo joinInfo;
        public ${beanName}Join(DataPackage dataPackage,DataPackage.JoinInfo joinInfo) {
            this.dataPackage = dataPackage;
            this.joinInfo = joinInfo;
        }
        public ${beanName}Join<P,R> on(String leftField, String rightField) {
            return ConditionSetting.joinOn(this,joinInfo,dataPackage,leftField, rightField);
        }
        public ${beanName}Join<P,R> on(BaseMapper<P> leftCondition, BaseMapper rightCondition) {
            return ConditionSetting.joinOn(this,joinInfo,leftCondition, rightCondition);
        }
        public ${beanName}Join<P,R> and(BaseMapper<P> baseMapper){
            return ConditionSetting.joinCondition(this,DataPackage.Way.AND,joinInfo,baseMapper);
        }
        public ${beanName}Join<P,R> or(BaseMapper<P> baseMapper){
             return ConditionSetting.joinCondition(this,DataPackage.Way.OR,joinInfo,baseMapper);
        }
    }

    public static class ${beanName}OrderBy<R> extends ${beanName}Fields<OrderBy<${beanName}OrderBy<R>>> {
        public ${beanName}OrderBy(DataPackage dataPackage) {
            this.dataPackage = dataPackage;
            this.t = new OrderBy<>(dataPackage, this);
        }
        public SelectExecution<R> EXEC() {
            return new SelectExecution<>(dataPackage);
        }
        public ${beanName}Where<SelectExecution<R>> WHERE() {
            return new ${beanName}Where<>(dataPackage, new SelectExecution<>(dataPackage));
        }
    }
    public static class ${beanName}Where<F> extends ${beanName}Fields<Where<${beanName}Where<F>, ${beanName}>> {
        private final F f;
        private ${beanName}Where(DataPackage dataPackage, F f) {
            this.dataPackage = dataPackage;
            this.t = new Where<>(dataPackage, this);
            this.f = f;
        }
        public ${beanName}Where<F> leftBracket() {
            ConditionSetting.setBracket(dataPackage,Expression.LeftBracket,DataPackage.Way.CUSTOM);
            return this;
        }
        public ${beanName}Where<F> orLeftBracket() {
            ConditionSetting.setBracket(dataPackage,Expression.LeftBracket,DataPackage.Way.OR);
            return this;
        }
        public ${beanName}Where<F> andLeftBracket() {
            ConditionSetting.setBracket(dataPackage,Expression.LeftBracket,DataPackage.Way.AND);
            return this;
        }
        public ${beanName}Where<F> rightBracket() {
            ConditionSetting.setBracket(dataPackage,Expression.RightBracket,DataPackage.Way.CUSTOM);
            return this;
        }
        public ${beanName}Where<F> eqToObj(Object obj){
            ConditionSetting.setObj(dataPackage,obj);
            return this;
        }
        public ${beanName}Where<F> closeLogicDeleteProtect(){
            dataPackage.setLogicDelete(Boolean.FALSE);
            return this;
        }
        public F EXEC() {
            return f;
        }
    }
    public static class ${beanName}Fields<T> extends BaseMapper<${beanName}>{
        protected T t;
    <#list properties2 as bean>
        /**
        *${bean.propertyDesc}
        */
        public T ${bean.propertyName}(){
            dataPackage.setField("${bean.propertyName}");
            return t;
        }
    </#list>
    }
<#if conf.exInlinePojo>
    /**
    * ${table.tableDesc}
    */
    <#if conf.useLombok>
    @Data
    </#if>
    @Table(name = "${table.tableName}")
    <#if conf.usePOJOSwagger2>
    @ApiModel("${beanName} ${table.tableDesc}")
    </#if>
    @FastBean
    public static class ${beanName} implements Serializable {
        private static final long serialVersionUID = 1L;

    <#list properties2 as bean>
    <#if (ids[bean.propertyName])??>
        <#if !conf.usePOJOSwagger2>
        /**
        *${bean.propertyDesc}
        */
        </#if>
        @Id
        @Column(name = "${propertiesAnColumns[bean.propertyName]}")
        <#if conf.usePOJOSwagger2>
        @ApiModelProperty(value = "${bean.propertyDesc}")
        </#if>
        private ${bean.propertyType} ${bean.propertyName};

        <#else>
        <#if !conf.usePOJOSwagger2>
        /**
        *${bean.propertyDesc}
        */
        </#if>
        @Column(name = "${propertiesAnColumns[bean.propertyName]}")
        <#if conf.usePOJOSwagger2>
        @ApiModelProperty(value = "${bean.propertyDesc}")
        </#if>
        private ${bean.propertyType} ${bean.propertyName};
        </#if>
    </#list>

    <#if !conf.useLombok>
        <#list keys as key>
        public ${properties["${key}"]} get${key?cap_first}() {
            return this.${key};
        }
        public void set${key?cap_first}(${properties["${key}"]} ${key}) {
            this.${key} = ${key};
        }

        </#list>
    </#if>
    }
</#if>
}